﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Reflection;
using System.Windows.Forms;
using HML.Design;

namespace HML
{
    /// <summary>
    /// 纵向分割线控件
    /// </summary>
    [Description("纵向分割线控件")]
    [DefaultProperty("Text")]
    [DefaultEvent("TextChanged")]
    [TypeConverter(typeof(PropertyOrderConverter))]
    [Designer(typeof(VHalvingLineDesigner))]
    [ToolboxItem(true)]
    [ToolboxBitmap(typeof(VHalvingLine), "Controls.HalvingLine.Resources.VHalvingLine.bmp")]
    public class VHalvingLine : DpiControl, ISkinObject
    {
        #region 主题

        private SkinObjectXmlMetadata skinObjectXmlMetadata = null;
        /// <summary>
        /// 主题对象在主题文件信息
        /// </summary>
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual SkinObjectXmlMetadata SkinObjectXmlMetadata
        {
            get
            {
                if (this.skinObjectXmlMetadata == null)
                    this.skinObjectXmlMetadata = new SkinObjectXmlMetadata(Assembly.GetAssembly(typeof(VHalvingLine)).GetName().Name, typeof(VHalvingLine).Name);

                return this.skinObjectXmlMetadata;
            }
        }

        private SkinController skinController = null;
        /// <summary>
        /// 主题控制器
        /// </summary>
        [Description("主题控制器")]
        [Category("杂项")]
        [PropertyOrder(-360)]
        [DefaultValue(null)]
        [RefreshProperties(RefreshProperties.All)]
        public virtual SkinController SkinController
        {
            get { return this.skinController; }
            set
            {
                if (this.skinController == value)
                    return;

                if (this.skinController != null)
                    this.skinController.RemoveSkinObject(this);

                this.skinController = value;

                if (this.skinController != null)
                    this.skinController.AddSkinObject(this);
            }
        }

        private SkinEnabledState skinEnabled= SkinEnabledState.Auto;
        /// <summary>
        /// 主题是否启用
        /// </summary>
        [Description("主题是否启用")]
        [Category("杂项")]
        [PropertyOrder(-300)]
        [DefaultValue(SkinEnabledState.Auto)]
        [RefreshProperties(RefreshProperties.All)]
        public virtual SkinEnabledState SkinEnabled
        {
            get { return this.skinEnabled; }
            set
            {
                if (this.skinEnabled == value)
                    return;

                this.skinEnabled = value;
                this.OnSkinChanged();
            }
        }

        private SkinStyle skinStyle = SkinStyle.Normal;
        /// <summary>
        /// 主题风格
        /// </summary>
        [Description("主题风格")]
        [Category("杂项")]
        [PropertyOrder(-260)]
        [DefaultValue(SkinStyle.Normal)]
        [RefreshProperties(RefreshProperties.All)]
        public virtual SkinStyle SkinStyle
        {
            get { return this.skinStyle; }
            set
            {
                if (this.skinStyle == value)
                    return;

                this.skinStyle = value;
                this.OnSkinChanged();
            }
        }

        private StyleAppearanceObject stateAppearance;
        /// <summary>
        /// 风格外观
        /// </summary>
        [Description("风格外观")]
        [Category("杂项")]
        [PropertyOrder(-200)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public StyleAppearanceObject StyleAppearance
        {
            get
            {
                if (this.stateAppearance == null)
                    this.stateAppearance = new StyleAppearanceObject(this, null);
                return this.stateAppearance;
            }
        }

        /// <summary>
        /// 主题已更改
        /// </summary>
        public virtual void OnSkinChanged()
        {
            SkinManager.SyncSkinValueToProperty(this);
            this.Invalidate();
        }

        private ISkinObject followSkinObject = null;
        /// <summary>
        /// 主题设置跟随指定主题对象（自己的设置不再生效，提供给代码使用）
        /// </summary>
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Localizable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual ISkinObject FollowSkinObject
        {
            get { return this.followSkinObject; }
            set
            {
                if (this.followSkinObject == value)
                    return;

                this.followSkinObject = value;
                this.OnSkinChanged();
            }
        }

        public virtual bool GetSkinObjectSkinStateCore()
        {
            return SkinManager.GetSkinObjectSkinState(this.FollowSkinObject ?? this);
        }

        void ISkinObject.InitializeInvalidate()
        {
            throw new NotImplementedException();
        }

        void ISkinObject.Invalidate()
        {
            this.Invalidate();
        }

        #endregion

        #region 停用事件

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler PaddingChanged
        {
            add { base.PaddingChanged += value; }
            remove { base.PaddingChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler TabIndexChanged
        {
            add { base.TabIndexChanged += value; }
            remove { base.TabIndexChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler TabStopChanged
        {
            add { base.TabStopChanged += value; }
            remove { base.TabStopChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler RightToLeftChanged
        {
            add { base.RightToLeftChanged += value; }
            remove { base.RightToLeftChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler ImeModeChanged
        {
            add { base.ImeModeChanged += value; }
            remove { base.ImeModeChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler BackgroundImageChanged
        {
            add { base.BackgroundImageChanged += value; }
            remove { base.BackgroundImageChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler BackgroundImageLayoutChanged
        {
            add { base.BackgroundImageLayoutChanged += value; }
            remove { base.BackgroundImageLayoutChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler BackColorChanged
        {
            add { base.BackColorChanged += value; }
            remove { base.BackColorChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler ForeColorChanged
        {
            add { base.ForeColorChanged += value; }
            remove { base.ForeColorChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler Click
        {
            add { base.Click += value; }
            remove { base.Click -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler DoubleClick
        {
            add { base.DoubleClick += value; }
            remove { base.DoubleClick -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event MouseEventHandler MouseClick
        {
            add { base.MouseClick += value; }
            remove { base.MouseClick -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event MouseEventHandler MouseDoubleClick
        {
            add { base.MouseDoubleClick += value; }
            remove { base.MouseDoubleClick -= value; }
        }
        #endregion

        #region 新增属性

        private HalvingLineStylePattern stylePattern = HalvingLineStylePattern.Solid;
        /// <summary>
        ///风格模式
        /// </summary>
        [Description("风格模式")]
        [Category("杂项")]
        [PropertyOrder(-200)]
        [DefaultValue(HalvingLineStylePattern.Solid)]
        public HalvingLineStylePattern StylePattern
        {
            get { return this.stylePattern; }
            set
            {
                if (this.stylePattern == value)
                    return;

                this.stylePattern = value;
                this.Invalidate();
            }
        }

        private int lineThickness = 1;
        /// <summary>
        ///线条厚度
        /// </summary>
        [Description("线条厚度")]
        [Category("杂项")]
        [PropertyOrder(-196)]
        [DefaultValue(1)]
        public int LineThickness
        {
            get { return this.lineThickness; }
            set
            {
                if (value < 1)
                    value = 1;
                if (this.lineThickness == value)
                    return;

                this.lineThickness = value;
                this.SetBoundsCore(this.Location.X, this.Location.Y, this.Width, this.Height, BoundsSpecified.Size);
                this.Invalidate();
            }
        }

        private VHalvingLineTextAlignment textAlignment = VHalvingLineTextAlignment.Center;
        /// <summary>
        ///文本对齐方式
        /// </summary>
        [Description("文本对齐方式")]
        [Category("杂项")]
        [PropertyOrder(-178)]
        [DefaultValue(VHalvingLineTextAlignment.Center)]
        public VHalvingLineTextAlignment TextAlignment
        {
            get { return this.textAlignment; }
            set
            {
                if (this.textAlignment == value)
                    return;

                this.textAlignment = value;
                this.SetBoundsCore(this.Location.X, this.Location.Y, this.Width, this.Height, BoundsSpecified.Size);
                this.Invalidate();
            }
        }

        private int textDistance = 40;
        /// <summary>
        ///文本位置偏移量(正数从左边开始偏移，负数由右边开始偏移)
        /// </summary>
        [Description("文本位置偏移量(正数从左边开始偏移，负数由右边开始偏移)")]
        [Category("杂项")]
        [PropertyOrder(-176)]
        [DefaultValue(40)]
        public int TextDistance
        {
            get { return this.textDistance; }
            set
            {
                if (this.textDistance == value || value < 0)
                    return;

                this.textDistance = value;
                this.Invalidate();
            }
        }

        #endregion

        #region 重写属性

        protected override Size DefaultSize
        {
            get { return new Size(16, 160); }
        }

        protected override ImeMode DefaultImeMode
        {
            get { return ImeMode.Disable; }
        }

        public override Font Font
        {
            get { return base.Font; }
            set
            {

                if (base.Font == value)
                    return;

                base.Font = value;
                this.SetBoundsCore(this.Location.X, this.Location.Y, this.Width, this.Height, BoundsSpecified.Size);
                this.Invalidate();
            }
        }

        public override string Text
        {
            get { return base.Text; }
            set
            {

                if (base.Text == value)
                    return;

                base.Text = value;
                this.SetBoundsCore(this.Location.X, this.Location.Y, this.Width, this.Height, BoundsSpecified.Size);
                this.Invalidate();
            }
        }

        #endregion

        #region 停用属性

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new Padding Padding
        {
            get { return base.Padding; }
            set { base.Padding = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new int TabIndex
        {
            get { return base.TabIndex; }
            set { base.TabIndex = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new bool TabStop
        {
            get { return base.TabStop; }
            set { base.TabStop = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public override RightToLeft RightToLeft
        {
            get { return base.RightToLeft; }
            set { base.RightToLeft = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new ImeMode ImeMode
        {
            get { return base.ImeMode; }
            set { base.ImeMode = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Image BackgroundImage
        {
            get { return base.BackgroundImage; }
            set { base.BackgroundImage = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override ImageLayout BackgroundImageLayout
        {
            get { return base.BackgroundImageLayout; }
            set { base.BackgroundImageLayout = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Color BackColor
        {
            get { return this.StyleAppearance.BackColor; }
            set { }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Color ForeColor
        {
            get { return this.StyleAppearance.TextColor; }
            set { }
        }

        #endregion

        public VHalvingLine()
        {
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            SetStyle(ControlStyles.StandardClick, false);
            SetStyle(ControlStyles.StandardDoubleClick, false);
            SetStyle(ControlStyles.Selectable, false);

            this.TabStop = false;
            this.OnSkinChanged();
        }

        #region 重写

        protected override void OnScaleDpiChangedInitialize()
        {
            this.SetBoundsCore(this.Location.X, this.Location.Y, this.Width, this.Height, BoundsSpecified.Size);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            Graphics g = e.Graphics;

            NativeMethods.TEXTMETRIC font_metrics = ControlHelper.GetFontMetrics(this.Handle, this.Font);
            int scale_lineThickness = this.LineThickness == 1 ? 1 : (int)Math.Ceiling(this.LineThickness * this.ScaleDpi);
            StringFormat text_sf = (StringFormat)StringFormat.GenericTypographic.Clone();
            text_sf.FormatFlags = StringFormatFlags.DirectionVertical;
            Size text_size = new Size(font_metrics.tmMaxCharWidth, (int)Math.Ceiling(g.MeasureString(this.Text, this.Font, int.MaxValue, text_sf).Height));

            // 文字
            if (!String.IsNullOrEmpty(this.Text))
            {
                int text_y = this.textDistance >= 0 ? (this.ClientRectangle.Y + this.textDistance + font_metrics.GetFontStereotypesMargim()) : (this.ClientRectangle.Bottom + this.textDistance - font_metrics.GetFontStereotypesMargim() - text_size.Height - font_metrics.GetFontStereotypesMargim());
                int text_x = 0;
                if (this.TextAlignment == VHalvingLineTextAlignment.Left)
                {
                    text_x = this.ClientRectangle.X;
                }
                else if (this.TextAlignment == VHalvingLineTextAlignment.Center)
                {
                    text_x = this.ClientRectangle.X + font_metrics.GetFontStereotypesMargim();
                }
                else if (this.TextAlignment == VHalvingLineTextAlignment.Right)
                {
                    text_x = this.ClientRectangle.Right - text_size.Width;
                }

                SolidBrush text_sb = new SolidBrush(this.StyleAppearance.TextColor);
                g.DrawString(this.Text, this.Font, text_sb, text_x, text_y, text_sf);
                text_sb.Dispose();
            }

            // 线条
            int line_splitter_width = (this.TextAlignment != VHalvingLineTextAlignment.Center || this.Text == "") ? 0 : text_size.Height;
            int line_splitter_y = this.textDistance >= 0 ? (this.ClientRectangle.Y + this.textDistance) : (this.ClientRectangle.Bottom + this.textDistance - line_splitter_width);
            float line_x = 0;
            if (this.TextAlignment == VHalvingLineTextAlignment.Left)
            {
                line_x = this.ClientRectangle.Right - (this.LineThickness == 1 ? this.LineThickness : scale_lineThickness / 2f);
            }
            else if (this.TextAlignment == VHalvingLineTextAlignment.Center)
            {
                line_x = this.ClientRectangle.X + this.ClientRectangle.Width / 2f;
            }
            else if (this.TextAlignment == VHalvingLineTextAlignment.Right)
            {
                line_x = this.ClientRectangle.X + (this.LineThickness == 1 ? 0 : scale_lineThickness / 2f);
            }

            Pen line_pen = new Pen(this.StyleAppearance.LineColor, scale_lineThickness) { Alignment = PenAlignment.Center, DashStyle = this.GetStyle() };
            g.DrawLine(line_pen, new PointF(line_x, this.ClientRectangle.Y), new PointF(line_x, line_splitter_y));
            g.DrawLine(line_pen, new PointF(line_x, line_splitter_y + line_splitter_width + ((this.TextAlignment == VHalvingLineTextAlignment.Center && this.Text != "") ? font_metrics.GetFontStereotypesMargim() : 0)), new PointF(line_x, this.ClientRectangle.Bottom));
            line_pen.Dispose();

            text_sf.Dispose();
        }

        protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
        {
            base.SetBoundsCore(x, y, this.GetControlAutoWidth(), height, specified);
        }

        #endregion

        #region 私有方法

        /// <summary>
        /// 根据字体计算控件宽度
        /// </summary>
        /// <returns></returns>
        private int GetControlAutoWidth()
        {
            NativeMethods.TEXTMETRIC font_metrics = ControlHelper.GetFontMetrics(this.Handle, this.Font);
            int scale_lineThickness = this.LineThickness == 1 ? 1 : (int)Math.Ceiling(this.LineThickness * this.ScaleDpi);

            if (this.TextAlignment == VHalvingLineTextAlignment.Center)
            {
                return Math.Max(scale_lineThickness, font_metrics.GetFontStereotypesMargim() + font_metrics.tmMaxCharWidth + font_metrics.GetFontStereotypesMargim());
            }
            else
            {
                return font_metrics.tmMaxCharWidth + font_metrics.GetFontStereotypesMargim() + scale_lineThickness;
            }
        }

        /// <summary>
        /// 获取显示风格
        /// </summary>
        /// <returns></returns>
        private DashStyle GetStyle()
        {
            if (this.StylePattern == HalvingLineStylePattern.Dash)
            {
                return DashStyle.Dash;
            }
            else if (this.StylePattern == HalvingLineStylePattern.DashDot)
            {
                return DashStyle.DashDot;
            }
            else if (this.StylePattern == HalvingLineStylePattern.DashDotDot)
            {
                return DashStyle.DashDotDot;
            }
            else if (this.StylePattern == HalvingLineStylePattern.Dot)
            {
                return DashStyle.Dot;
            }
            return DashStyle.Solid;

        }

        #endregion

        #region 外观

        public class StyleAppearanceObject : AppearanceObjectBase
        {
            internal StyleAppearanceObject(ISkinObject owner, AppearanceObjectBase parent) : base(owner, parent) { }

            #region 属性

            private Color skinBackColor = Color.Empty;
            private readonly Color defaultBackColor = SystemColors.Control;
            private Color backColor = Color.Empty;
            /// <summary>
            /// 背景颜色
            /// </summary>
            [Description("背景颜色")]
            [PropertyOrder(-195)]
            [SkinProperty(true, true)]
            public Color BackColor
            {
                get
                {
                    if (this.owner.GetSkinObjectSkinStateCore() && this.skinBackColor != Color.Empty)
                    {
                        return this.skinBackColor;
                    }

                    if (this.backColor != Color.Empty)
                    {
                        return this.backColor;
                    }

                    if (((Control)this.owner).Parent != null)
                    {
                        return ((Control)this.owner).Parent.BackColor;
                    }

                    return this.defaultBackColor;
                }
                set
                {
                    if (this.backColor == value)
                        return;

                    this.backColor = value;
                    this.Invalidate();
                }
            }
            private bool ShouldSerializeBackColor()
            {
                return this.backColor != Color.Empty;
            }
            private void ResetBackColor()
            {
                this.backColor = Color.Empty;
                this.Invalidate();
            }

            private Color skinTextColor = Color.Empty;
            private readonly Color defaultTextColor = SystemColors.ControlText;
            private Color textColor = Color.Empty;
            /// <summary>
            /// 文本颜色
            /// </summary>
            [Description("文本颜色")]
            [PropertyOrder(-193)]
            [SkinProperty(true, true)]
            public Color TextColor
            {
                get
                {
                    if (this.owner.GetSkinObjectSkinStateCore() && this.skinTextColor != Color.Empty)
                    {
                        return this.skinTextColor;
                    }

                    if (this.textColor != Color.Empty)
                    {
                        return this.textColor;
                    }

                    if (((Control)this.owner).Parent != null)
                    {
                        return ((Control)this.owner).Parent.ForeColor;
                    }

                    return this.defaultTextColor;
                }
                set
                {
                    if (this.textColor == value)
                        return;

                    this.textColor = value;
                    this.Invalidate();
                }
            }
            private bool ShouldSerializeTextColor()
            {
                return this.textColor != Color.Empty;
            }
            private void ResetTextColor()
            {
                this.textColor = Color.Empty;
                this.Invalidate();
            }

            private Color skinLineColor = Color.Empty;
            private readonly Color defaultLineColor = SystemColors.ActiveCaption;
            private Color lineColor = Color.Empty;
            /// <summary>
            /// 线条颜色
            /// </summary>
            [Description("线条颜色")]
            [PropertyOrder(-190)]
            [Editor(typeof(AlphaColorEditor), typeof(UITypeEditor))]
            [SkinProperty(true, false)]
            public Color LineColor
            {
                get
                {
                    if (this.owner.GetSkinObjectSkinStateCore())
                    {
                        return this.skinLineColor;
                    }

                    if (this.lineColor != Color.Empty)
                    {
                        return this.lineColor;
                    }

                    return this.defaultLineColor;
                }
                set
                {
                    if (this.lineColor == value)
                        return;

                    this.lineColor = value;
                    this.Invalidate();
                }
            }
            private bool ShouldSerializeLineColor()
            {
                return this.lineColor != Color.Empty;
            }
            private void ResetLineColor()
            {
                this.lineColor = Color.Empty;
                this.Invalidate();
            }

            #endregion

        }

        #endregion

    }

}
